﻿using Owin;
using System;
using King.Box.Owin;
using Microsoft.Owin;
using System.Web.Http;
using King.Box.Utils.Global;
using Microsoft.Owin.Security.OAuth;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json;
using Autofac;
using Microsoft.Owin.Cors;
using King.Box.WebApi.Filter;
using CatClient;
using System.Net.Http.Formatting;
using System.Reflection;

namespace King.Box.WebApi.AppStart
{
    public class ApiServer
    {
        private AppServer _appServer;
        public static ApiServer Instance => InstanceLazy.Value;

        private static readonly Lazy<ApiServer> InstanceLazy = new Lazy<ApiServer>();

        public void Start()
        {
            _appServer = new AppServer();
            var port = GlobalConfig.Port;

            Action<IAppBuilder, HttpConfiguration> action = (app, config) =>
               {
                   StartupAutoMapper.Initialize();
                   StartupAutofac.Instance.Register(config);

                   config.Register();
                   config.ConfigureAuth();
                   config.ConfigureJsonFormatter();
                   config.SuppressDefaultHostAuthentication();
                   config.Filters.Add(new ExceptionHandlerAttribute());
                   config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));

                   app.UseRequestScopeContext();
                   app.UseCors(CorsOptions.AllowAll);
                   app.UseOAuthAuthorizationServer(HttpConfigruationExtend.OAuthOptions);
                   app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
               };
            _appServer.Start(port, action);

            var appName = Assembly.GetExecutingAssembly().GetName().Name;

            Console.WriteLine($"{ appName } is start on http port :{ port }");

            CatConfig.Init();
        }

        public void Stop()
        {
            try
            {
                StartupAutofac.Instance.Dispose();

                _appServer?.Stop();
            }
            catch { }
        }
    }

    public static class HttpConfigruationExtend
    {
        #region Routes
        public static void Register(this HttpConfiguration config)
        {
            config.MapHttpAttributeRoutes();
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{action}/{id}",
                defaults: new { controller = "Main", action = "Index", id = RouteParameter.Optional }
            );
        }
        #endregion

        #region OAuth
        public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
        public static string PublicClientId { get; private set; }
        public static void ConfigureAuth(this HttpConfiguration config)
        {
            OAuthOptions = new OAuthAuthorizationServerOptions
            {
                AllowInsecureHttp = true,
                TokenEndpointPath = new PathString("/token"),
                AccessTokenExpireTimeSpan = TimeSpan.FromDays(7),
                Provider = StartupAutofac.Instance.Container.Resolve<IOAuthAuthorizationServerProvider>()
            };
        }
        #endregion

        #region Json
        public static void ConfigureJsonFormatter(this HttpConfiguration config)
        {
            var jsonConfig = new JsonMediaTypeFormatter();
            jsonConfig.SerializerSettings.Formatting = Formatting.Indented;
            jsonConfig.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
            jsonConfig.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
            jsonConfig.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
            jsonConfig.SerializerSettings.DateFormatHandling = DateFormatHandling.MicrosoftDateFormat;
            jsonConfig.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver()
            {
                IgnoreSerializableAttribute = true
            };

            config.Formatters.Clear();
            config.Formatters.Add(jsonConfig);
        }
        #endregion
    }
}